package com.tools.common.io;

import com.tools.common.object.Note;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;

/**
 * NIO 拷贝和执行写入操作时的包装类
 * */
@Note("NIO 拷贝和执行写入操作时的包装类")
public final class NIOCopyBean {

    @Note("文件输入管道流")
    private FileChannel input;

    @Note("文件输出管道流")
    private FileChannel output;

    @Note("缓冲区大小，单位为字节")
    private int bufferSize;

    /* *******************************************************************************************
     *
     *          构造器
     *
     * *******************************************************************************************
     * */

    public NIOCopyBean() {}

    public static NIOCopyBean of() {
        return new NIOCopyBean();
    }

    /* *******************************************************************************************
     *
     *          Getter / Setter
     *
     * *******************************************************************************************
     * */

    public FileChannel getInput() {
        return input;
    }

    public void setInput(FileChannel input) {
        if(input == null) {
            this.closeAll();
            throw new NullPointerException("文件输入管道流 input FileChannel 不能为 null");
        }
        this.input = input;
    }

    public void setInput(FileInputStream inputStream) {
        try {
            if(inputStream == null) throw new NullPointerException();
            this.input = inputStream.getChannel();
            IOKit.close(inputStream);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setInput(File inFile) {
        try {
            if(inFile == null) throw new NullPointerException();
            this.input = IOKit.fileInputChannel(inFile);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setInput(String inPath) {
        try {
            if(inPath == null || inPath.isEmpty()) throw new NullPointerException();
            this.input = IOKit.fileInputChannel(inPath);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public FileChannel getOutput() {
        return output;
    }

    public void setOutput(FileChannel output) {
        if(output == null) {
            this.closeAll();
            throw new NullPointerException("文件输出管道流 output FileChannel 不能为 null");
        }
        this.output = output;
    }

    public void setOutput(FileOutputStream outputStream) {
        try {
            if(outputStream == null) throw new NullPointerException();
            this.output = outputStream.getChannel();
            IOKit.close(outputStream);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setOutput(File outFile) {
        try {
            if(outFile == null) throw new NullPointerException();
            this.output = IOKit.fileOutputChannel(outFile, false);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setOutput(File outFile, boolean append) {
        try {
            if(outFile == null) throw new NullPointerException();
            this.output = IOKit.fileOutputChannel(outFile, append);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setOutput(String outPath) {
        try {
            if(outPath == null || outPath.isEmpty()) throw new NullPointerException();
            this.output = IOKit.fileOutputChannel(outPath, false);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public void setOutput(String outPath, boolean append) {
        try {
            if(outPath == null || outPath.isEmpty()) throw new NullPointerException();
            this.output = IOKit.fileOutputChannel(outPath, append);
        } catch (Throwable e) {
            this.closeAll();
            throw e;
        }
    }

    public int getBufferSize() {
        return bufferSize;
    }

    public void setBufferSize(int bufferSize) {
        this.bufferSize = bufferSize;
    }

    @Override
    public String toString() {
        return "NIOCopyBean{" +
                "input=" + input +
                ", output=" + output +
                ", bufferSize=" + bufferSize +
                '}';
    }

    public boolean initInputChannel() {
        return input != null;
    }

    public boolean initOutputChannel() {
        return output != null;
    }

    public boolean enableCopy() {
        return input != null && output != null;
    }

    public int getBufferSizeOrReplace(int bufferSize) {
        return (this.bufferSize <= 0) ? bufferSize : this.bufferSize;
    }

    public void closeInput() {
        IOKit.close(input);
        input = null;
    }

    public void closeOutput() {
        IOKit.close(output);
        output = null;
    }

    public void closeAll() {
        closeInput();
        closeOutput();
    }

    public void copy() {
        IOKit.copy(this);
    }

    /* *******************************************************************************************
     *
     *          链式调用
     *
     * *******************************************************************************************
     * */

    public NIOCopyBean input(FileChannel input) {
        this.setInput(input);
        return this;
    }

    public NIOCopyBean input(FileInputStream inputStream) {
        this.setInput(inputStream);
        return this;
    }

    public NIOCopyBean input(File inFile) {
        this.setInput(inFile);
        return this;
    }

    public NIOCopyBean input(String inPath) {
        this.setInput(inPath);
        return this;
    }

    public NIOCopyBean output(FileChannel output) {
        this.setOutput(output);
        return this;
    }

    public NIOCopyBean output(FileOutputStream outputStream) {
        this.setOutput(outputStream);
        return this;
    }

    public NIOCopyBean output(File outFile) {
        this.setOutput(outFile);
        return this;
    }

    public NIOCopyBean output(File outFile, boolean append) {
        this.setOutput(outFile, append);
        return this;
    }

    public NIOCopyBean output(String outPath) {
        this.setOutput(outPath);
        return this;
    }

    public NIOCopyBean output(String outPath, boolean append) {
        this.setOutput(outPath, append);
        return this;
    }

    public NIOCopyBean bufferSize(int bufferSize) {
        this.setBufferSize(bufferSize);
        return this;
    }
}
